home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 007 / protobnu.lqr / TERMINAL.PAS < prev   
Encoding:
Pascal/Delphi Source File  |  1985-06-13  |  42.6 KB  |  1,356 lines

  1. {$C-}
  2. {$V-}
  3.  
  4. program terminal;  {This is a terminal handling package by Jim Nutt
  5.                     CIS - 71076,1434 or EIS - 76044,1155.
  6.                     It is public domain and not to be sold
  7.                     vidtex compatible
  8.                     CIS-A file transfers}
  9.  
  10. {$u-}  {Serial I/O drivers start here}
  11.  
  12. Const
  13.      RECV_BUF_SIZE = 4096;             {this may be changed to
  14.                                         whatever size you need}
  15.     DEFAULT_BAUD   = 1200;
  16. { *** Port addresses *** }
  17.      THR = $3F8;                       {Transmitter Holding Register: the
  18.                                         serial port address we use to send
  19.                                         data}
  20.      IER = $3F9;                       {Interrupt Enable Register for the
  21.                                         serial port}
  22.      LCR = $3FB;                       {Line Control Register for the serial
  23.                                         port. Determines data bits, stop bits
  24.                                         and parity, contributes to setting
  25.                                         baud-rate}
  26.      MCR = $3FC;                       {Modem Control Register}
  27.      LSR = $3FD;                       {Line Status Register}
  28.      MSR = $3FE;                       {Modem Status Register}
  29.      IMR = $021;                       {Interrupt Mask Register port address
  30.                                         of Intel 8259A Programmable Interrupt
  31.                                         controller}
  32. { *** Masks *** }
  33.      ENABLE_OUT2 = 8;                  {Setting bit 3 of MCR enables OUT2}
  34.      ENABLE_DAV = 1;                   {Setting bit 0 of IER enables Data
  35.                                         AVailable interrupt from serial port}
  36.      ENABLE_IRQ4 = $EF;                {Clearing bit 5 of IMR enables serial
  37.                                         interrupts to reach the CPU}
  38.      DISABLE_OUT2 = 1;                 {Clearing MCR disables OUT2}
  39.      DISABLE_DAV = 0;                  {Clearing IER disables Data
  40.                                        AVailable interrupt from serial port}
  41.      DISABLE_IRQ4 = $10;               {Setting bit 5 of IMR stops serial
  42.                                         interrupts from reaching the CPU}
  43.      SET_BAUD = $80;                   {Setting bit 7 of LCR allows us to set
  44.                                         the baud rate of the serial port}
  45.      SET_PARMS = $7F;                  {Clearing bit 7 of LCR allows us to set
  46.                                         non-baud-rate parameters on the
  47.                                         serial port}
  48.  
  49. Type
  50.     parity_set        = (none,even);    {readability and expansion}
  51.     bigstring        = string[80];
  52.  
  53. Var
  54.    buf_start, buf_end    : integer;    {NOTE: these will change by them-
  55.                                         selves in the background}
  56.    recv_buffer           : array [1..RECV_BUF_SIZE] of byte;
  57.                                        {also self-changing}
  58.    speed                 : integer;    {I don't know the top speed these
  59.                                         routines will handle}
  60.    dbits                 : 7..8;       {only ones most people use}
  61.    stop_bits             : 1..2;       {does anyone use 2?}
  62.    parity                : parity_set;  {even and none are the common ones}
  63.  
  64. function cgetc(TimeLimit : integer) : integer;
  65. {if a byte is recieved at COM1: in less than TimeLimit seconds,
  66.  returns byte as an integer, else returns -1}
  67.  
  68. const 
  69.      TIMED_OUT = -1;
  70. begin
  71.      TimeLimit := TimeLimit shl 10;     {convert TimeLimit to millisecs}
  72.      while (buf_start = buf_end) and (TimeLimit > 0) do
  73.        begin
  74.           delay(1);
  75.           TimeLimit := pred(TimeLimit)
  76.        end;
  77.      if (TimeLimit >= 0) and (buf_start <> buf_end)
  78.        then
  79.          begin
  80.            inline ($FA);            {suspend interrupts}
  81.            cgetc := recv_buffer[buf_start];
  82.            buf_start := succ(buf_start);
  83.            if buf_start > RECV_BUF_SIZE
  84.              then
  85.                buf_start := 1;
  86.            inline ($FB);            {resume interrupts}
  87.          end
  88.        else
  89.          cgetc := TIMED_OUT;
  90. end;
  91.  
  92. procedure send(c : byte);
  93.  
  94. var 
  95.    a : byte;
  96. begin
  97.   repeat
  98.        a := port[LSR]
  99.   until odd(a shr 5);
  100.   port[THR] := c;
  101. end;
  102.  
  103. procedure StrSend(s : bigstring);
  104.  
  105. var
  106.    i : integer;
  107. begin
  108.      for i := 1 to length(s) do
  109.          begin
  110.            send(ord(s[i]));
  111.            delay(10);
  112.          end
  113. end;
  114.  
  115. procedure SendPaced(s : bigstring);
  116.  
  117. label 
  118.      99;
  119.  
  120. const 
  121.      CRSYM = '<';
  122.  
  123. var 
  124.    i : integer;
  125.    c : integer;
  126. begin
  127.      for i := 1 to Length(s) do
  128.        begin
  129.           if s[i] = CRSYM
  130.             then
  131.               send(13)
  132.             else
  133.               send(ord(s[i]));
  134.           c := cgetc(1);
  135.           if c <> -1
  136.             then
  137.               write(chr(c))
  138.             else begin
  139.                    sound(440);
  140.                    delay(20);
  141.                    nosound;
  142.                    goto 99
  143.               end
  144.        end;
  145.   99:
  146. end;
  147.  
  148. {Communications routines for TURBO Pascal written by Alan Bishop,
  149.  modified slightly by Scott Murphy.
  150.  Handles standart COM1: ports with interrupt handling.  Includes
  151.  support for only one port, and with no overflow, parity, or other
  152.  such checking.  However, even some of the best communication programs
  153.  don't do this anyway, and I never use it.  If you make modifications,
  154.  please send me a copy if you have a simple way of doing it (CIS EMAIL,
  155.  Usenet, MCI Mail, etc)  Hope these are useful.
  156.  
  157. Alan Bishop - CIS      - 72405,647
  158.               Usenet   - bishop@ecsvax
  159.               MCI Mail - ABISHOP
  160. }
  161.  
  162. procedure update_uart;
  163. {uses dbits, stop_bits, and parity}
  164.  
  165. var 
  166.    newparm, oldLCR : byte;
  167. begin
  168.   newparm := dbits-5;
  169.   if stop_bits = 2
  170.     then newparm := newparm + 4;
  171.   if parity = even
  172.     then newparm := newparm + 24;
  173.   oldLCR := port[LCR];
  174.   port[LCR] := oldLCR and SET_PARMS;
  175.   port[LCR] := newparm;
  176. end;
  177.  
  178.  
  179. procedure term_ready(state : boolean);
  180. {if state = TRUE then set RTS true else set false}
  181.  
  182. var 
  183.    OldMCR : byte;
  184. begin
  185.      OldMCR := port[MCR];
  186.      if state
  187.        then
  188.          port[MCR] := OldMCR or 1
  189.        else
  190.          port[MCR] := OldMCR and $FE
  191. end;
  192.  
  193. function carrier : boolean;
  194. {true if carrier, false if not}
  195. begin
  196.   carrier := odd(port[MSR] shr 7);
  197. end;
  198.  
  199. procedure set_up_recv_buffer;
  200. begin
  201.   buf_start := 1;
  202.   buf_end   := 1;
  203. end;
  204.  
  205. procedure new_baud(rate : integer);
  206. {has no problems with non-standard bauds}
  207.  
  208. var
  209.    OldLCR : byte;
  210. begin
  211.   if rate <= 9600
  212.     then
  213.       begin
  214.         speed := rate;
  215.         rate := trunc(115200.0/rate);
  216.         OldLCR := port[LCR] or SET_BAUD;
  217.         port[LCR] := OldLCR;
  218.         port[THR] := lo(rate);
  219.         port[IER] := hi(rate);
  220.         port[LCR] := OldLCR and SET_PARMS;
  221.       end;
  222. end;
  223.  
  224. procedure init_port;
  225. {installs interrupt sevice routine for serial port}
  226.  
  227. var a,b : integer;
  228.     buf_len : integer;
  229. begin
  230.   update_uart;
  231.   new_baud(speed);
  232.   buf_len := RECV_BUF_SIZE;
  233.  
  234.  {this is the background routine}
  235.  
  236.   inline (
  237.               $1E/                     {push ds}
  238.               $0E/                     {push cs}
  239.               $1F/                     {pop  ds                  ;ds := cs}
  240.               $BA/*+23/                {mov  dx, offset ISR}
  241.               $B8/$0C/$25/             {mov  ax, 250CH           ;set COM1: vector}
  242.               $CD/$21/                 {int  21H}
  243.               $8B/$BE/BUF_LEN/         {mov  di, buf_len}
  244.               $89/$3E/*+87/            {mov  lcl_buf_len,di}
  245.               $1F/                     {pop  ds}
  246.               $2E/$8C/$1E/*+83/        {mov  lcl_ds, ds}
  247.               $EB/$51/                 {jmp  exit}
  248. {ISR:}        $FB/                     {sti}
  249.               $1E/                     {push ds}
  250.               $50/                     {push ax}
  251.               $53/                     {push bx}
  252.               $52/                     {push dx}
  253.               $56/                     {push si}
  254.               $2E/$8E/$1E/*+70/        {mov  ds,[lcl_ds]}
  255.               $BA/$F8/$03/             {mov  dx, 3F8H           ;address RBR}
  256.               $EC/                     {in   al, dx             ;read rbr}
  257.               $BE/RECV_BUFFER/
  258.           {mov  si, recv_buffer    ;address start of recv_buffer}
  259.               $8B/$1E/BUF_END/
  260.           {mov  bx, [buf_end]      ;index of current char in recv_buffer}
  261.               $88/$40/$FF/             {mov  [bx+si-1],al       ;copy char to recv_buffer}
  262.               $43/                     {inc  bx                 ;update buf_end}
  263.               $E8/$22/$00/             {call adj_idx}
  264.               $89/$1E/BUF_END/         {mov  [buf_end],bx}
  265.               $3B/$1E/BUF_START/       {cmp  bx, [buf_start]}
  266.               $75/$0C/                 {jnz  ISR_DONE}
  267.               $8B/$1E/BUF_START/       {mov  bx,buf_start}
  268.               $43/                     {inc  bx}
  269.               $E8/$10/$00/             {call adj_idx}
  270.               $89/$1E/BUF_START/       {mov  [buf_start],bx}
  271.               $BA/$20/$00/             {mov  dx,20H            ;EOI command for 8259A PIC}
  272.               $B0/$20/                 {mov  al,20H            ;EOI port for 8259A PIC}
  273.               $EE/                     {out  dx,al             ;End Of Interrupt}
  274.               $5E/                     {pop  si}
  275.               $5A/                     {pop  dx}
  276.               $5B/                     {pop  bx}
  277.               $58/                     {pop  ax}
  278.               $1F/                     {pop  ds}
  279.               $CF/                     {iret}
  280. {adj_idx:}    $2E/$8B/$16/*+11/        {mov  dx,[lcl_buf_len]}
  281.               $42/                     {inc  dx}
  282.               $39/$DA/                 {cmp  dx,bx}
  283.               $75/$03/                 {jnz  no_change}
  284.               $BB/$01/$00/             {mov  bx,1}
  285. {no_change:}  $C3/                     {ret}
  286. {lcl_buf_len;}$00/$00/                 {dw  0}
  287.               $00/$01/                 {dw  1}
  288. {exit:}       $90                      {nop}
  289.   );
  290.   port[IER] := ENABLE_DAV;              {interrupt enable}
  291.   a := port[MCR];
  292.   port[MCR] := a or ENABLE_OUT2;        {preserve RTS and enable OUT2}
  293.   a := port[IMR];
  294.   a := a and ENABLE_IRQ4;
  295.   port[IMR]  := a;
  296. end;
  297.  
  298.  
  299. procedure remove_port;
  300. {disables DAV, OUT2 and IRQ4 so that COM1: will no longer be serviced}
  301.  
  302. var
  303.    a : byte;
  304. begin
  305.      a         := port[IMR];
  306.      port[IMR] := a or DISABLE_IRQ4;
  307.      port[IER] := DISABLE_DAV;
  308.      a         := port[MCR];
  309.      port[MCR] := a and DISABLE_OUT2;
  310. end;
  311.  
  312.  
  313. procedure break;
  314. {send a break}
  315.  
  316. var a,b : byte;
  317. begin
  318.   a := port[LCR];
  319.   b := (a and $7F) or $40;
  320.   port[LCR] := b;
  321.   delay(400);
  322.   port[LCR] := a;
  323. end;
  324.  
  325. procedure setup;
  326. {initialize most stuff - you may want to replace this routine completely}
  327. begin
  328.   dbits        := 8;
  329.   parity       := none;
  330.   stop_bits    := 1;
  331.   speed        := DEFAULT_BAUD;
  332.   init_port;
  333.   term_ready(true);
  334. end;
  335. {$u+}
  336.  
  337. const
  338.   minint = -32767;
  339.  
  340. type
  341.   buftype = array[0..520] of char;
  342.   bigbuf  = array[minint..maxint] of byte;
  343.   wstr    = string[60];
  344.  
  345. var
  346.   parms         : wstr;
  347.   tstr          : wstr;
  348.   number        : wstr;
  349.   old_carrier   : boolean;
  350.   kch           : char;
  351.   quit          : boolean;
  352.   rcvd          : integer;
  353.   save          : boolean;
  354.   buffer        : ^bigbuf;
  355.   buffptr       : integer;
  356.   i,j           : integer;
  357.   blocks        : integer;
  358.   bytes         : integer;
  359.   total_bytes   : real;
  360.   left4         : boolean;
  361.   left1         : boolean;
  362.   left256       : boolean;
  363.   capture       : file;
  364.   filename      : string[14];
  365.   found         : boolean;
  366.   monitor       : boolean;
  367.   current_block : integer;
  368.   dummy         : boolean;
  369.  
  370. procedure purge;
  371.  
  372.   begin
  373.     repeat
  374.     until cgetc(1) = -1;
  375.   end;
  376.  
  377. function upper(tstr : wstr) : wstr;
  378.  
  379.   var
  380.     i : integer;
  381.  
  382.   begin
  383.     for i := 1 to length(tstr) do
  384.       tstr[i] := upcase(tstr[i]);
  385.   end;
  386.  
  387. procedure stat_write(tstr : wstr);
  388.  
  389.   var
  390.     x,y : integer;
  391.  
  392.   begin
  393.     x := wherex;
  394.     y := wherey;
  395.     textcolor(0);
  396.     textbackground(7);
  397.     window(1,1,80,25);
  398.     gotoxy(1,25);
  399.     clreol;
  400.     write(output,tstr);
  401.     gotoxy(65,25);
  402.     write('Terminal 1.0');
  403.     window(1,1,80,24);
  404.     textcolor(7);
  405.     textbackground(0);
  406.     gotoxy(x,y);
  407.   end;
  408.  
  409. function stat_read(pstr : wstr) : wstr;
  410.  
  411.   var
  412.     x,y  : integer;
  413.     tstr : wstr;
  414.  
  415.   begin
  416.     x := wherex;
  417.     y := wherey;
  418.     textcolor(0);
  419.     textbackground(7);
  420.     window(1,1,80,25);
  421.     gotoxy(1,25);
  422.     clreol;
  423.     write(output,pstr);
  424.     gotoxy(65,25);
  425.     write('Terminal 1.0');
  426.     gotoxy(length(pstr) + 1,25);
  427.     read(tstr);
  428.     stat_read := tstr;
  429.     window(1,1,80,24);
  430.     textcolor(7);
  431.     textbackground(0);
  432.     gotoxy(x,y);
  433.   end;
  434.  
  435. procedure dial;
  436.  
  437.   var
  438.     parms,number,tstr : wstr;
  439.     phonefile         : text;
  440.  
  441.     begin
  442.       parms := stat_read('Number to dial? ');
  443.       number := parms;
  444.       stat_write('Dialing ' + number + '....');
  445.       strsend('ATDT' + number + ^M);
  446.       purge;
  447.       repeat
  448.       until
  449.       cgetc(0) <> -1;
  450.       purge;
  451.       if old_carrier
  452.         then
  453.           stat_write('Dialing ' + number + '....Connected')
  454.         else
  455.           stat_write('Dialing ' + number + '....No Carrier');
  456.     end;
  457.  
  458. procedure identify;
  459.  
  460.   begin
  461.     stat_write('Sending Identification...');
  462.     strsend('#IBM PC PCDOS,CC,PA,PB,DT,CB,SS9p,WC'+^m);
  463.     stat_write('Connected');
  464.   end;
  465.  
  466. procedure acknowledge(block : byte);
  467.  
  468.   begin
  469.   send(16);
  470.   send((block mod 10) + 48);
  471.   end;
  472.  
  473.  
  474. {$Iprotocol.pas}
  475.  
  476. procedure A_protocol;
  477.  
  478.   const
  479.     ESCAPE = $1B;
  480.     SI     = $0F;
  481.     SO     = $0E;
  482.     SOH    = $01;
  483.     ETX    = $03;
  484.     EOT    = $04;
  485.     ENQ    = $05;
  486.     DLE    = $10;
  487.     A_EOF  = $1A;
  488.     A_ACK  = '.';
  489.     A_NAK  = '/';
  490.     A_ABORT  = $11;
  491.  
  492.   var
  493.     count : integer;
  494.     recvd : integer;
  495.     done  : boolean;
  496.  
  497.   procedure filetrana;
  498.  
  499.     var
  500.       recnum   : integer;
  501.       tstr     : wstr;
  502.       size     : wstr;
  503.       checksum : integer;
  504.       areclen  : integer;
  505.       arecord  : buftype;
  506.       status   : integer;
  507.       i        : integer;
  508.  
  509.     function increc(c : integer) : integer;
  510.  
  511.       begin
  512.         if c = ord('9')
  513.           then
  514.             increc := ord('0')
  515.           else
  516.             increc := c + 1;
  517.       end;
  518.  
  519.     function getarecord(var arecord : buftype) : integer;
  520.  
  521.       var
  522.         retries : integer;
  523.         recvd   : integer;
  524.         gotchk  : integer;
  525.         buffptr : integer;
  526.         line    : bigstring;
  527.         return  : integer;
  528.         stat    : integer;
  529.  
  530.       function getmask : integer;
  531.  
  532.         var
  533.           ch : integer;
  534.  
  535.         begin
  536.           repeat
  537.             ch := cgetc(0);
  538.           until ch > 0;
  539.           if ch = DLE
  540.             then
  541.               ch := (cgetc(30) and $1F) or 256;
  542.           getmask := ch;
  543.         end;
  544.  
  545.       function getcheck : integer;
  546.  
  547.         var
  548.           ch : integer;
  549.           c  : integer;
  550.  
  551.         begin
  552.           ch := getmask;
  553.           if ch <> ETX
  554.             then
  555.               begin
  556.                 c := ch and $FF;
  557.                 if (checksum and $80) = 0
  558.                   then
  559.                     checksum := checksum shl 1
  560.                   else
  561.                     checksum := ((checksum shl 1) and $FF) + 1;
  562.                 checksum := checksum + c;
  563.                 if checksum >= $100
  564.                   then
  565.                     checksum := (checksum + 1) and $FF;
  566.               end;
  567.           getcheck := ch;
  568.         end;
  569.  
  570.       begin
  571.         return := 1;
  572.         retries := 1;
  573.         while (retries < 10) and (return = 1) do
  574.           begin
  575.             retries := retries + 1;
  576.             repeat
  577.               stat := cgetc(30);
  578.             until (stat = -1) or (stat = SOH) or ((stat and $7f) = SOH);
  579.             stat := stat and $7f;
  580.             if SOH = stat
  581.               then
  582.                 begin
  583.                   checksum := 0;
  584.                   recvd := getcheck and $7F;
  585.                   if increc(recvd) = recnum
  586.                     then
  587.                       begin
  588.                         stat_write('Invalid record number (off by 1)');
  589.                         purge;
  590.                         send(ord(A_ACK));
  591.                       end
  592.                     else
  593.                       if recvd <> recnum
  594.                         then
  595.                           begin
  596.                             stat_write('Invalid record number: ' + chr(recvd + 48));
  597.                             purge;
  598.                             send(ord(A_NAK));
  599.                           end
  600.                         else
  601.                           begin
  602.                             areclen := 0;
  603.                             buffptr := 0;
  604.                             recvd := getcheck;
  605.                             while ETX <> recvd do
  606.                               begin
  607.                                 arecord[buffptr] := chr(recvd);
  608.                                 buffptr := succ(buffptr);
  609.                                 areclen := succ(areclen);
  610.                                 if (areclen mod 16) = 0
  611.                                   then
  612.                                     begin
  613.                                       tstr := tstr + '.';
  614.                                       stat_write(tstr);
  615.                                     end;
  616.                                 recvd := getcheck;
  617.                               end;
  618.  
  619.                             gotchk := getmask and $FF;
  620.                             if checksum = gotchk
  621.                               then
  622.                                 begin
  623.                                   tstr := '';
  624.                                   recnum := increc(recnum);
  625.                                   return := 0;
  626.                                 end
  627.                               else
  628.                                 begin
  629.                                   stat_write(' NAK');
  630.                                   tstr := copy(tstr,1,12);
  631.                                   stat_write(tstr);
  632.                                   purge;
  633.                                   send(ord(A_NAK));
  634.                                 end;
  635.                           end;
  636.                 end;
  637.           end;
  638.         if return = 1
  639.           then
  640.             begin
  641.               stat_write('Too many retries');
  642.               send(ord(^U));
  643.               getarecord := 1;
  644.             end
  645.           else
  646.             getarecord := 0;
  647.       end;
  648.  
  649.     procedure a_download(var arecord : buftype);
  650.  
  651.       var 
  652.         filename : string[30];
  653.         dowfile  : file of byte;
  654.         i,ch     : integer;
  655.         end_file : byte;
  656.         tint     : integer;
  657.         rply     : char;
  658.         abort    : boolean;
  659.         done     : boolean;
  660.         f_eof    : boolean;
  661.         outbyte  : byte;
  662.  
  663.       begin
  664.         stat_write('File download requested');
  665.         abort := false;
  666.         done  := false;
  667.         i := 2;
  668.         filename := '';
  669.         while arecord[i] <> ^M do
  670.           begin
  671.             filename := filename + arecord[i];
  672.             i := succ(i);
  673.           end;
  674.       {$i-} {turn of io checking}
  675.         assign(dowfile,filename);
  676.         reset(dowfile);
  677.         if ioresult = 0
  678.           then
  679.             begin
  680.               close(dowfile);
  681.               stat_write('The file, "' + filename +
  682.                          '", already exists.  Overwrite it? (y/n)');
  683.               read(kbd,rply);
  684.               abort := not(rply in ['Y','y']);
  685.             end;
  686.  
  687.         if not abort
  688.           then
  689.             begin
  690.               rewrite(dowfile);
  691.               abort := ioresult <> 0;
  692.               if abort
  693.                 then
  694.                   stat_write('Unable to open/create, "' + filename + '"');
  695.             end;
  696.  
  697.         if not abort
  698.           then
  699.             begin
  700.               tstr := 'Receiving file: ' + filename + ' as ';
  701.               if arecord[1] = 'B'
  702.                 then
  703.                   begin
  704.                     end_file := 4;
  705.                     stat_write(tstr + 'a binary file.');
  706.                   end
  707.                 else
  708.                   begin
  709.                     end_file := 26;
  710.                     stat_write(tstr + 'as an ascii file.');
  711.                   end;
  712.               while not done do
  713.                 begin
  714.                   str(longfilesize(dowfile): 6: 0,size);
  715.                   tstr := chr(recnum) + ' (' + size + '):  ';
  716.                   stat_write(tstr);
  717.                   purge;
  718.                   send(ord(A_ACK));
  719.                   if getarecord(arecord) <> 0
  720.                     then
  721.                       begin
  722.                         stat_write('Communications failure!');
  723.                         close(dowfile);
  724.                         done := true;
  725.                       end
  726.                     else
  727.                       begin
  728.                         i := 0;
  729.                         f_eof := i >= areclen;
  730.                         while not f_eof do
  731.                           if ((arecord[i] = chr(EOT)) and (areclen = 1)) or
  732.                              ((arecord[i] = chr(A_EOF)) and (end_file = A_EOF))
  733.                             then
  734.                               begin
  735.                                 f_eof := true;
  736.                                 close(dowfile);
  737.                                 stat_write('download complete.');
  738.                                 purge;
  739.                                 send(ord(A_ACK));
  740.                               end
  741.                             else
  742.                               begin
  743.                                 outbyte := byte(arecord[i]);
  744.                                 write(dowfile,outbyte);
  745.                                 flush(dowfile);
  746.                                 i := succ(i);
  747.                                 f_eof := i >= areclen;
  748.                               end;
  749.                         if i < areclen
  750.                           then
  751.                             done := true;
  752.                       end;
  753.                 end;
  754.             end;
  755.       end;
  756.  
  757.   procedure a_upload;
  758.  
  759.     var 
  760.       filename : string[30];
  761.       upfile   : file of byte;
  762.       i        : integer;
  763.       ch       : byte;
  764.       end_hit,
  765.       abort,
  766.       done     : boolean;
  767.  
  768.     function sendrecord : integer;
  769.  
  770.       var
  771.         retries : integer;
  772.         acknak  : integer;
  773.         quit    : boolean;
  774.  
  775.       procedure putrecord;
  776.  
  777.         var
  778.           i : integer;
  779.           checksum : integer;
  780.  
  781.         procedure putmasked(ch : integer);
  782.  
  783.             begin
  784.               if not((areclen = 1) and (ch = eot))
  785.                 then
  786.                   if ch in [$1..$4,$10,$15]
  787.                     then
  788.                       begin
  789.                         send(DLE);
  790.                         send(ch + $40);
  791.                       end
  792.                     else
  793.                       send(ch and $ff)
  794.                 else
  795.                   send(ch and $ff);
  796.             end;
  797.  
  798.         procedure putcheck(ch : integer);
  799.  
  800.           var
  801.             c : integer;
  802.  
  803.             begin
  804.               c := ch and $ff;
  805.               if (checksum and $80) = 0
  806.                 then
  807.                   checksum := checksum shl 1
  808.                 else
  809.                   checksum := ((checksum shl 1) and $ff) + 1;
  810.               checksum := checksum + c;
  811.               if checksum >= $100
  812.                 then
  813.                   checksum := $ff and (checksum + 1);
  814.               putmasked(ch);
  815.             end;
  816.  
  817.           begin
  818.             send(SOH);
  819.             checksum := 0;
  820.             putcheck(recnum);
  821.             for i := 0 to areclen - 1 do
  822.               begin
  823.                 putcheck(ord(arecord[i]));
  824.                 if (i mod 32) = 0
  825.                   then
  826.                     begin
  827.                       tstr := tstr + '.';
  828.                       stat_write(tstr);
  829.                     end;
  830.               end;
  831.             send(ETX);
  832.             putmasked(checksum);
  833.           end;
  834.  
  835.         begin
  836.           retries := 0;
  837.           quit    := false;
  838.           while (retries < 10) and not(quit) do
  839.             begin
  840.               retries := succ(retries);
  841.               tstr := tstr + chr(recnum);
  842.               stat_write(tstr);
  843.               putrecord;
  844.               acknak := cgetc(10);
  845.               if acknak = ord(A_ACK)
  846.                 then
  847.                   begin
  848.                     recnum := increc(recnum);
  849.                     quit := true;
  850.                     sendrecord := 0;
  851.                   end
  852.                 else if acknak = A_ABORT
  853.                        then
  854.                          begin
  855.                            stat_write('Abort!');
  856.                            sendrecord := 1;
  857.                            quit := true;
  858.                          end
  859.                        else if acknak = ord(A_NAK)
  860.                               then
  861.                                 begin
  862.                                   stat_write('NAK: ' + chr(acknak));
  863.                                   tstr := copy(tstr,1,14);
  864.                                   stat_write(tstr);
  865.                                   quit := false;
  866.                                 end;
  867.             end;
  868.  
  869.           if acknak = ord(A_NAK)
  870.             then
  871.               begin
  872.                 send(A_ABORT);
  873.                 stat_write('Too many retries!');
  874.                 sendrecord := 1;
  875.               end;
  876.         end;
  877.  
  878.       begin
  879.         tstr := 'Preparing to upload "';
  880.         i := 2;
  881.         filename := '';
  882.         while arecord[i] <> ^M do
  883.           begin
  884.             filename := filename + arecord[i];
  885.             i := succ(i);
  886.           end;
  887.         stat_write(tstr + filename + '".');
  888.       {$i-} {turn of io checking}
  889.         assign(upfile,filename);
  890.         reset(upfile);
  891.         if ioresult = 0
  892.           then
  893.             begin
  894.               str(longfilesize(upfile): 0: 0,tstr);
  895.               stat_write('"' + filename + '" is ' + tstr + ' bytes long.');
  896.               send(ord(A_ACK));
  897.               repeat
  898.               until ord(A_ACK) = cgetc(10);
  899.               repeat
  900.                 tstr := '';
  901.                 areclen := 0;
  902.                 str(longfilepos(upfile)/longfilesize(upfile)*100: 5: 1,size);
  903.                 tstr := size + '% (';
  904.                 str(longfilepos(upfile): 7: 0,size);
  905.                 tstr := tstr + size + ') -- ';
  906.                 stat_write(tstr);
  907.                 repeat
  908.                   read(upfile,ch);
  909.                   arecord[areclen] := chr(ch);
  910.                   areclen := areclen + 1;
  911.                 until eof(upfile) or (areclen > 256);
  912.  
  913.                 if sendrecord <> 0
  914.                   then
  915.                     begin
  916.                       abort := true;
  917.                       close(upfile);
  918.                       stat_write('Communications failure !');
  919.                     end
  920.                   else
  921.                     abort := false;
  922.               until abort or eof(upfile);
  923.  
  924.               if not abort
  925.                 then
  926.                   begin
  927.                     tstr := '';
  928.                     arecord[0] := chr(EOT);
  929.                     areclen := 1;
  930.                     str(longfilepos(upfile)/longfilesize(upfile)*100: 5: 1,size);
  931.                     tstr := size + '% (';
  932.                     str(longfilepos(upfile): 7: 0,size);
  933.                     tstr := tstr + size + ') -- ';
  934.                     stat_write(tstr);
  935.                     ch := sendrecord;
  936.                     close(upfile);
  937.                   end;
  938.             end
  939.           else
  940.             begin
  941.               stat_write('Cannot open "' + filename + '".');
  942.               send(A_ABORT);
  943.             end;
  944.       end;
  945.  
  946.     begin
  947.       stat_write('File transfer requested');
  948.       recnum := ord('1');
  949.       repeat
  950.         status := getarecord(arecord);
  951.       until (status = 0) or keypressed;
  952.       if status = 0
  953.         then
  954.           case arecord[0] of
  955.             'U' : a_upload;
  956.             'D' : a_download(arecord);
  957.           end;
  958.     end;
  959.  
  960.  
  961.   begin
  962.     done := false;
  963.     repeat
  964.       recvd := cgetc(10);
  965.       if recvd > 0
  966.         then
  967.           begin
  968.             recvd := recvd and $7F;
  969.             while (recvd = SI) or (recvd = -1) or (recvd = 143) do
  970.               recvd := cgetc(1);
  971.             if recvd <> SO
  972.               then
  973.                 begin
  974.                   if recvd = ESCAPE
  975.                     then
  976.                       repeat
  977.                         recvd := cgetc(0) and $7F;
  978.                         case char(recvd) of
  979.                           'I' : identify;
  980.                           'A' : filetrana;
  981.                           'G' : {graphics;}
  982.                         end;
  983.                       until recvd in [65,71,73,SO,SI]
  984.                     else
  985.                       done := true;
  986.                   recvd := cgetc(1);
  987.                 end
  988.           end
  989.         else
  990.           done := true;
  991.       done := done or keypressed or (recvd = SO);
  992.     until done;
  993.     stat_write('Connected');
  994.   end;
  995.  
  996. procedure escape;
  997.  
  998.   var
  999.     rcvd : integer;
  1000.     ch   : char;
  1001.     x,y  : integer;
  1002.  
  1003.   procedure esc_esc;
  1004.  
  1005.     var
  1006.       rcvd  : integer;
  1007.       ch    : char;
  1008.       x,y   : integer;
  1009.       x1,y1 : integer;
  1010.  
  1011.     begin
  1012.     rcvd := cgetc(1);
  1013.     if rcvd > 0 then
  1014.       case rcvd of
  1015.         079 : save := true;
  1016.         067 : save := false;
  1017.         090 : begin
  1018.               buffptr := minint;
  1019.               left4 := false;
  1020.               left1 := false;
  1021.               left256 := false;
  1022.               end;
  1023.         087 : begin
  1024.               y := cgetc(5) - 31;
  1025.               x := cgetc(5) - 31;
  1026.               y1 := cgetc(5) - 31;
  1027.               x1 := cgetc(5) - 31;
  1028.               window(x,y,x1,y1);
  1029.               end;
  1030.         end;
  1031.     end;
  1032.  
  1033.   begin
  1034.     rcvd := cgetc(1);
  1035.     if rcvd > 0
  1036.       then
  1037.         case rcvd and $7F of
  1038.           27 : esc_esc;
  1039. {          108: textmode(c40);
  1040.           109: textmode(c80);
  1041.  }         89 : begin
  1042.                  y := cgetc(1) - 31;
  1043.                  x := cgetc(1) - 31;
  1044.                  gotoxy(x,y);
  1045.                end;
  1046.           65 : gotoxy(wherex,wherey - 1);
  1047.           66 : gotoxy(wherex,wherey + 1);
  1048.           67 : gotoxy(wherex + 1,wherey);
  1049.           68 : gotoxy(wherex - 1,wherey);
  1050.           71 : {graphics};
  1051.           72 : gotoxy(1,1);
  1052.           73 : identify;
  1053.           75 : clreol;
  1054.           74 : begin
  1055.                  clreol;
  1056.                  for y := wherey + 1 to 25 do
  1057.                    begin
  1058.                      gotoxy(1,y);
  1059.                      clreol;
  1060.                    end;
  1061.                end;
  1062.           106 : clrscr;
  1063.         end;
  1064.   end;
  1065.  
  1066. {$u-}
  1067. begin {terminal}
  1068.   stat_write('Initializing');
  1069.   clrscr;
  1070.   buffptr := minint;
  1071.   save := false;
  1072.   left1 := false;
  1073.   left4 := false;
  1074.   left256 := false;
  1075.   new(buffer);
  1076.   set_up_recv_buffer;
  1077.   setup;
  1078.   quit   := false;
  1079.   stat_write('Ready');
  1080.   monitor := false;
  1081.   old_carrier := false;
  1082.   current_block := 1;
  1083.  
  1084.   repeat
  1085.     if old_carrier xor carrier
  1086.       then
  1087.         begin
  1088.           old_carrier := carrier;
  1089.           if old_carrier
  1090.             then
  1091.               stat_write('Connected')
  1092.             else
  1093.               stat_write('No Carrier');
  1094.         end;
  1095.  
  1096.     if keypressed
  1097.       then
  1098.         begin
  1099.           read(kbd,kch);
  1100.           if kch = ^[
  1101.             then
  1102.               if keypressed then
  1103.               begin
  1104.                 read(kbd,kch);
  1105.                 case ord(kch) of
  1106.                   50 : monitor := monitor xor true;
  1107.                   32 : dial;
  1108.                   25 : begin
  1109.                          parms := stat_read('Set parameter (parameter,value) ?');
  1110.                          i := 1;
  1111.                          while i <= length(parms) do
  1112.                            begin
  1113.                              case parms[i] of
  1114.                                'f','F' : begin
  1115.                                            filename := copy(parms,pos(',',parms) + 1,
  1116.                                                        length(parms) - pos(',',parms));
  1117.                                            i := length(parms) + 1;
  1118.                                          end;
  1119.                                'b','B' : begin
  1120.                                            i := length(parms) + 1;
  1121.                                            tstr := copy(parms,pos(',',parms) + 1,
  1122.                                                    length(parms) - pos(',',parms));
  1123.                                            parms := '';
  1124.                                            for i := 1 to length(tstr) do
  1125.                                              if tstr[i] in ['0'..'9']
  1126.                                                then
  1127.                                                  parms := parms + tstr[i];
  1128.                                            val(parms,j,i);
  1129.                                            if i = 0
  1130.                                              then
  1131.                                                speed := j;
  1132.                                            stat_write('New Baud Rate: ' + parms);
  1133.                                            init_port;
  1134.                                            delay(2000)
  1135.                                          end;
  1136.                                'p','P' : begin
  1137.                                            i := length(parms) + 1;
  1138.                                            tstr := copy(parms,pos(',',parms) + 1,
  1139.                                                    length(parms) - pos(',',parms));
  1140.                                            j := 1;
  1141.                                            while j <= length(tstr) do
  1142.                                              case tstr[j] of
  1143.                                                'e','E' : begin
  1144.                                                            parity := even;
  1145.                                                            j := length(tstr) + 1
  1146.                                                          end;
  1147.                                                'n','N' : begin
  1148.                                                            parity := none;
  1149.                                                            j := length(tstr) + 1;
  1150.                                                          end
  1151.                                                else
  1152.                                                  j := j + 1;
  1153.                                              end;
  1154.                                            stat_write('New parity: '+ tstr);
  1155.                                            init_port;
  1156.                                            delay(2000);
  1157.                                          end;
  1158.                                's','S' : begin
  1159.                                            tstr := copy(parms,pos(',',parms) + 1,
  1160.                                                    length(parms) - pos(',',parms));
  1161.                                            parms := '';
  1162.                                            for i := 1 to length(tstr) do
  1163.                                              if tstr[i] in ['1','2']
  1164.                                                then
  1165.                                                  parms := tstr[i];
  1166.                                            val(parms,j,i);
  1167.                                            if i = 0
  1168.                                              then
  1169.                                                stop_bits := j;
  1170.                                            stat_write('New Stop Bits: ' + parms);
  1171.                                            init_port;
  1172.                                            delay(2000)
  1173.                                          end;
  1174.  
  1175.                                'w','W' : begin
  1176.                                            tstr := copy(parms,pos(',',parms) + 1,
  1177.                                                    length(parms) - pos(',',parms));
  1178.                                            parms := '';
  1179.                                            for i := 1 to length(tstr) do
  1180.                                              if tstr[i] in ['7','8']
  1181.                                                then
  1182.                                                  parms := tstr[i];
  1183.                                            val(parms,j,i);
  1184.                                            if i = 0
  1185.                                              then
  1186.                                                dbits := j;
  1187.                                            stat_write('New Data Bits: ' + parms);
  1188.                                            init_port;
  1189.                                            delay(2000)
  1190.                                          end;
  1191.  
  1192.                                'd','D' : begin
  1193.                                            tstr := 'Current: ';
  1194.                                            str(speed,parms);
  1195.                                            tstr := tstr + parms + ' baud, ';
  1196.                                            str(dbits,parms);
  1197.                                            tstr := tstr + parms + ' data bits, ';
  1198.                                            str(stop_bits,parms);
  1199.                                            tstr := tstr + parms + ' stop bits, ';
  1200.                                            if parity = none
  1201.                                              then
  1202.                                                tstr := tstr + 'no parity';
  1203.                                            if parity = even
  1204.                                              then
  1205.                                                tstr := tstr + 'even parity';
  1206.                                            stat_write(tstr);
  1207.                                            delay(2000);
  1208.                                          end;
  1209.  
  1210.                              else
  1211.                                i := i + 1;
  1212.                            end;
  1213.                        end;
  1214.                   if old_carrier
  1215.                     then
  1216.                       stat_write('Connected')
  1217.                     else
  1218.                       stat_write('No Carrier');
  1219.                 end;
  1220.                 31 : begin
  1221.                        save := true;
  1222.                        stat_write('Capture buffer on');
  1223.                        delay(100);
  1224.                        if old_carrier
  1225.                          then
  1226.                            stat_write('Connected')
  1227.                          else
  1228.                            stat_write('No Carrier');
  1229.                      end;
  1230.                 46 : begin
  1231.                        save := false;
  1232.                        stat_write('Capture buffer off');
  1233.                        delay(100);
  1234.                        if old_carrier
  1235.                          then
  1236.                            stat_write('Connected')
  1237.                          else
  1238.                            stat_write('No Carrier');
  1239.                      end;
  1240.                 17 : begin
  1241.                        stat_write('Saving capture buffer to "' + filename + '"');
  1242.                        assign(capture,filename);
  1243.                {$i-}
  1244.                        reset(capture);
  1245.                        if ioresult = 0
  1246.                          then
  1247.                            longseek(capture,longfilesize(capture))
  1248.                          else
  1249.                            rewrite(capture);
  1250.                        blockwrite(capture,buffer^,((buffptr + 32767) div 128) + 2);
  1251.                        str((((buffptr + 32767) div 128) + 1): 5,tstr);
  1252.                        stat_write(tstr);
  1253.                        delay(2000);
  1254.                        close(capture);
  1255.                        buffptr := minint;
  1256.                        if old_carrier
  1257.                          then
  1258.                            stat_write('Connected')
  1259.                          else
  1260.                            stat_write('No Carrier');
  1261.                      end;
  1262.                 37 : begin
  1263.                        stat_write('Clearing capture buffer');
  1264.                        delay(100);
  1265.                        buffptr := minint;
  1266.                        left4 := false;
  1267.                        left1 := false;
  1268.                        left256 := false;
  1269.                        if old_carrier
  1270.                          then
  1271.                            stat_write('Connected')
  1272.                          else
  1273.                            stat_write('No Carrier');
  1274.                      end;
  1275.                 45 : begin
  1276.                        quit := true;
  1277.                        stat_write('Exiting...');
  1278.                      end;
  1279.                 35 : begin
  1280.                        term_ready(false);
  1281.                        delay(10);
  1282.                        stat_write('Disconnecting...');
  1283.                        term_ready(true);
  1284.                      end;
  1285.               end;
  1286.         end
  1287.         else
  1288.           send(ord(kch))
  1289.       else
  1290.         send(ord(kch));
  1291.       end;
  1292.  
  1293.     if not quit
  1294.       then
  1295.         begin
  1296.  
  1297.           rcvd := cgetc(0);
  1298.  
  1299.           if save and (rcvd > 0)
  1300.             then
  1301.               begin
  1302.                 if (buffptr > (maxint - 4096)) and not left4
  1303.                   then
  1304.                     begin
  1305.                       left4 := true;
  1306.                       stat_write('Only 4k left in capture buffer');
  1307.                     end;
  1308.                 if (buffptr > (maxint - 1024)) and not left1
  1309.                   then
  1310.                     begin
  1311.                       left1 := true;
  1312.                       stat_write('Only 1k left in capture buffer');
  1313.                     end;
  1314.                 if (buffptr > (maxint - 256)) and not left256
  1315.                   then
  1316.                     begin
  1317.                       left256 := true;
  1318.                       stat_write('Only 256 bytes left in capture buffer');
  1319.                     end;
  1320.                 if buffptr = maxint
  1321.                   then
  1322.                     begin
  1323.                       stat_write('Capture buffer closed.');
  1324.                       save := false;
  1325.                     end
  1326.                   else
  1327.                     begin
  1328.                       buffer^[buffptr] := rcvd and $7f;
  1329.                       buffptr := succ(buffptr);
  1330.                     end;
  1331.               end;
  1332.  
  1333.           if rcvd > 0
  1334.             then
  1335.             if monitor then
  1336.               write(rcvd:4)
  1337.             else
  1338.               case rcvd and $7F of
  1339.                 15      : A_protocol;
  1340.                 05      : dummy := do_transfer;
  1341.                 12      : clrscr;
  1342.                 13      : write(^M);
  1343.                 10      : write(^J);
  1344.                 08      : write(^h,' ',^h);
  1345.                 27      : escape;
  1346.                 32..255 : write(chr(rcvd and $7F));
  1347.               end;
  1348.         end;
  1349.  
  1350.   until quit;
  1351.   dispose(buffer);
  1352.   remove_port;
  1353.   textbackground(0);
  1354.   textcolor(7);
  1355. end.
  1356.